﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Vortex.Drawing {

	/// <summary>
	/// Value of shader parameter
	/// </summary>
	public class ParamValue {
		private byte[] _data;

		/// <summary>
		/// Gets the float point value data.
		/// </summary>
		/// <value>The param value.</value>
		public byte[] Data {
			get { return _data; }
		}

		/// <summary>
		/// Sets the value bytes.
		/// </summary>
		/// <param name="data">The value data.</param>
		/// <param name="byteCount">The byte count of value.</param>
		private unsafe void SetBytes(void* data, int byteCount) {
			_data = new byte[byteCount];
			byte* byteData = (byte*)data;
			for (int n = 0; n < byteCount; ++n) {
				_data[n] = byteData[n];
			}
		}

		#region Float Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="ShaderParamValue"/>.
		/// </summary>
		/// <param name="value">The <see cref="System.Single"/> value.</param>
		public ParamValue(float value) {			
			unsafe {
				SetBytes(&value, sizeof(float));
			}
		}

		public ParamValue (float[] values) {
			if (null == values) throw new ArgumentNullException("values");
			if (values.Length < 1) throw new ArgumentException("Values array should be not empty", "values");
			
			unsafe {
				fixed (float* data = &values[0]) {
					SetBytes(data, sizeof(float) * values.Length);
				}
			}
		}

		public ParamValue (Vector2 value) {
			unsafe {
				SetBytes(&value, sizeof(Vector2));
			}
		}

		public ParamValue (Vector3 value) {
			unsafe {
				SetBytes(&value, sizeof(Vector3));
			}
		}

		public ParamValue (Vector4 value) {
			unsafe {
				SetBytes(&value, sizeof(Vector4));
			}
		}

		public ParamValue (Rect value) {
			unsafe {
				SetBytes(&value, sizeof(Rect));
			}
		}

		public ParamValue (ColorU color) {
			unsafe {
				float* values = stackalloc float[4];
				values[0] = color.Bf;
				values[1] = color.Gf;
				values[2] = color.Rf;
				values[3] = color.Af;
				SetBytes(values, sizeof(float) * 4);
			}
		}

		public ParamValue (Transform2D value) {
			unsafe {
				SetBytes(&value, sizeof(Transform2D));
			}
		}

		public ParamValue (Matrix value) {
			unsafe {
				SetBytes(&value, sizeof(Matrix));
			}
		}

		public ParamValue(ref Transform2D value) {
			unsafe {
				fixed (Transform2D* data = &value) {
					SetBytes(data, sizeof(Transform2D));
				}
			}
		}

		public ParamValue(ref Matrix value) {
			unsafe {
				fixed (Matrix* data = &value) {
					SetBytes(data, sizeof(Matrix));
				}
			}
		}

		public ParamValue(int value) {
			unsafe {
				SetBytes(&value, sizeof(int));
			}
		}

		public ParamValue(bool value) {
			unsafe {
				SetBytes(&value, sizeof(bool));
			}
		}

		#endregion

		#region Operators

		public static implicit operator ParamValue(float value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(float[] values) {
			return new ParamValue(values);
		}

		public static implicit operator ParamValue(Vector2 value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(Vector3 value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(Vector4 value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(Rect value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(Transform2D value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(Matrix value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(ColorU value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(bool value) {
			return new ParamValue(value);
		}

		public static implicit operator ParamValue(int value) {
			return new ParamValue(value);
		}
		
		#endregion
	}
}
